11320. Amazing trick
Alice is a magician, and she creates a new
trick. She has n cards with different numbers
from 1 to n written on them. First, she asks an
audience member to shuffle the deck and put the cards in a row. Let the number
on the i-th card from the left be ai.
Then Alice selects two permutations p and
q. There is a restriction on p and q: permutations can’t
have fixed points. In other words, ∀i: pi ≠ i and qi ≠ i.
Once the permutations are chosen, Alice
shuffles the cards according to them. Now the i-th card from the left becomes
the card a[p[q[i]]. The trick is considered
successful if, after shuffling, the number on the i-th card from the left
is i.
Help Alice choose the permutations p and q,
or determine if it is impossible for the given starting permutation a.
Input. The first line contains the number of test cases t (1
≤ t ≤ 105).
Each test is described in two lines. The
first line contains one integer n (1 ≤ n ≤ 105) – the
number of cards. The second line contains n integers ai (1 ≤ ai ≤ n, ∀i ≠ j: ai ≠ aj)
– the initial permutation of the cards.
It is guaranteed that the sum of n over
all tests does not exceed 105.
Output. Print the answer for each test case in the order they
appear in the input.
For each test case, print “Impossible” on a
single line if no solution exists.
Otherwise, print “Possible” on the first
line, followed by two lines containing the permutations p and q.
Sample
input |
Sample
output |
4 2 2 1 3 1 2 3 4 2 1 4 3 5 5 1 4 2 3 |
Impossible Possible 3 1 2 2 3 1 Possible 3 4 2 1 3 4 2 1 Possible 4 1 2 5 3 3 1 4 5 2 |
combinatorics
Algorithm
analysis
Let’s consider three permutations: a,
p, and q. Let I be the identity permutation. Consider the
equation: a(p(q( I ))) =
I. From this, we get p(q( I )) = a-1.
Using the fact that permutations are applied from right to left, this identity
can be rewritten as: p °
q = a-1. Therefore, q = p-1 ° a-1.
Generate a random permutation p that
has no fixed points. Then, compute the permutation q = p-1 °
a-1 and check that it has no fixed
points. The found permutations p and q are the required ones.
Example
Consider
the permutation a
= (5, 1, 4, 2, 3).
Its
inverse will be a-1 = (2, 4, 5, 3, 1).
Generate
a random permutation p with no fixed points. For example, let p = (4, 1, 2, 5, 3).
Now, let’s compute its inverse: p-1 = (2, 3, 5, 1, 4).
Next,
compute q = p-1 °
a-1 = (2, 3, 5, 1, 4) ° (2, 4, 5, 3, 1) = (3,
1, 4, 5, 2). The permutation q has no fixed points, so it is
valid.
Algorithm realization
The
print function prints the elements of the array a,
starting from the first one.
void print(vector<int>& a)
{
for (int i = 1; i < a.size(); i++)
printf("%d ", a[i]);
printf("\n");
}
The
function is_valid checks whether the permutation v
contains any fixed points.
bool is_valid(vector<int>& v)
{
for (int i = 1; i < v.size(); i++)
if (v[i] == i) return false;
return true;
}
Declare
the arrays.
vector<int> a, p, p1, q;
The
main part of the program. Read the input data.
scanf("%d", &tests);
while (tests--)
{
scanf("%d", &n);
Initialize
the arrays.
a.resize(n + 1);
p1.resize(n + 1);
p.resize(n + 1);
q.resize(n + 1);
Read
the input permutation a and immediately store its inverse in the array a.
That is, the array a contains the permutation a-1, where a is the input
permutation.
for (i = 1; i <= n; i++)
{
scanf("%d", &x);
a[x] = i;
}
mt19937
is one of the standard pseudorandom number generators in C++ (Mersenne Twister
with a period of 19937). It is very fast and has good statistical properties,
making it an excellent choice for most tasks requiring random number
generation.
mt19937 gen(random_device{}());
In the variable found, we’ll mark whether a
solution is found for the current test.
found = false;
Perform 1000 iterations.
for (it = 0; it < 1000;
it++)
{
Generate a random permutation. To do this, populate the
array p with the numbers 0, 1, 2, …, and use the shuffle
function to shuffle the elements, starting from the first (non-zero) element. We
work with permutations from 1 to n.
iota(p.begin(), p.end(), 0);
shuffle(p.begin() + 1, p.end(), gen);
Check whether the permutation p is valid (i.e., it
contains no fixed points).
if (!is_valid(p)) continue;
Compute the permutation p1 = p-1.
for (i = 1; i <= n; i++)
p1[p[i]] = i;
Compute the permutation q = p1
° a-1 = p-1 °
a-1.
for (i = 1; i <= n; i++)
q[i] = p1[a[i]];
If the permutation q is valid, print the result.
if (is_valid(q))
{
puts("Possible");
print(p);
print(q);
found = true;
break;
}
}
If no solution is found after 1000 iterations, then no
solution exists.
if (!found) puts("Impossible");
}